package com.example.hospital.api.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.BiMap;
import cn.hutool.core.map.MapUtil;
import com.example.hospital.api.controller.form.vo.DoctorScheduleSlotVO;
import com.example.hospital.api.db.dao.DoctorDao;
import com.example.hospital.api.db.dao.DoctorWorkPlanDao;
import com.example.hospital.api.db.dao.DoctorWorkPlanScheduleDao;
import com.example.hospital.api.db.pojo.DoctorWorkPlanEntity;
import com.example.hospital.api.db.pojo.DoctorWorkPlanScheduleEntity;
import com.example.hospital.api.exception.HospitalException;
import com.example.hospital.api.service.DoctorWorkPlanScheduleService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Baiken
 * @version 1.0
 * @description: 出诊业务层
 * @date 2024/9/9 下午6:07
 */

@Service
public class DoctorWorkPlanScheduleServiceImpl implements DoctorWorkPlanScheduleService {
    @Resource
    private DoctorWorkPlanScheduleDao doctorWorkPlanScheduleDao;

    @Resource
    private DoctorDao doctorDao;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private DoctorWorkPlanDao doctorWorkPlanDao;

    private BiMap<String,Integer> range = new BiMap<>(new HashMap(){{
        put("08:00",1);
        put("08:30",2);
        put("09:00",3);
        put("09:30",4);
        put("10:00",5);
        put("10:30",6);
        put("11:00",7);
        put("11:30",8);
        put("13:00",9);
        put("13:30",10);
        put("14:00",11);
        put("14:30",12);
        put("15:00",13);
        put("15:30",14);
        put("16:00",15);
    }});

    @Transactional
    public void insertScheduleHandle(ArrayList<DoctorWorkPlanScheduleEntity> list){
        for(DoctorWorkPlanScheduleEntity entity : list){
            doctorWorkPlanScheduleDao.insert(entity);
        }
    }

    private void addScheduleCache(ArrayList<DoctorWorkPlanScheduleEntity> list){
        //如果list中没有元素,就不需要缓存
        if(list == null || list.isEmpty()) {
            return;
        }
        //一个出诊计划中插入到schedule数据表的时间段记录的外键值向同,取出列表中第一个元素获取的外键
        int workPlanId = list.get(0).getWorkPlanId();

        //查询记录

        ArrayList<HashMap> newList = doctorWorkPlanScheduleDao.searchNewSchedule(workPlanId);

        for(HashMap one : newList){
            int id = MapUtil.getInt(one,"id");
            int slot = MapUtil.getInt(one,"slot");

            //定义缓存的key
            String key = "doctor_schedule_" + id;

            //缓存出诊时间到redis
            redisTemplate.opsForHash().putAll(key,one);

            //出诊日期
            String date = MapUtil.getStr(one,"date");

            //该时间的其实时间
            String time = range.getKey(slot);

            //设置缓存过期时间
            redisTemplate.expireAt(key, DateUtil.parse(date + " " + time));
        }
    }

    @Override
    public void insert(ArrayList<DoctorWorkPlanScheduleEntity> entity) {
        this.insertScheduleHandle(entity);
        //TODO 设置Redis缓存
        addScheduleCache(entity);
    }

    @Override
    public ArrayList<HashMap> searchByDeptSubId(int deptSubId) {
        ArrayList<HashMap> list = doctorDao.searchByDeptSubId(deptSubId);
        return list;
    }

    @Override
    public HashMap searchByWorkPlanId(int workPlanId) {
        ArrayList<HashMap> list = doctorWorkPlanScheduleDao.searchByWorkPlanId(workPlanId);
        HashMap result = new HashMap();
        ArrayList temp = new ArrayList();
        for(int i = 0 ; i < list.size() ; i++){
            HashMap map = list.get(i);
            int scheduleId = MapUtil.getInt(map,"scheduleId");
            int doctorId = MapUtil.getInt(map,"doctorId");
            int maximum = MapUtil.getInt(map,"maximum");
            int num = MapUtil.getInt(map,"num");
            int slot = MapUtil.getInt(map,"slot");

            if(i == 0){
                result.put("doctorId",doctorId);
                result.put("maximum",maximum);
            }
            temp.add(new HashMap<>(){{
                put("scheduleId",scheduleId);
                put("slot",slot);
                put("num",num);
            }});
        }
        result.put("slots",temp);
        return result;
    }

    @Override
    public ArrayList searchDeptSubSchedule(Map param) {
        ArrayList<HashMap> list = doctorWorkPlanScheduleDao.searchDeptSubSchedule(param);
        ArrayList<HashMap> result = new ArrayList();

        int tempDoctorId = 0;
        HashMap doctor = new HashMap();

        for (HashMap map : list) {
            int doctorId = MapUtil.getInt(map, "doctorId");
            int slot = MapUtil.getInt(map, "slot");
            //如果当前记录跟上一条记录的医生不是同一个人
            if (tempDoctorId != doctorId) {
                tempDoctorId = doctorId;
                doctor = map;
                doctor.replace("slot", new ArrayList<Integer>() {{
                    add(slot);
                }});
                result.add(doctor);
            }
            //如果当前记录与上一条记录是同一个医生
            else if (tempDoctorId == doctorId) {
                ArrayList<Integer> slotList = (ArrayList) doctor.get("slot");
                slotList.add(slot);
            }
        }
        //筛选哪些时段出诊，哪些时段不出诊
        for (HashMap map : result) {
            ArrayList<Integer> slot = (ArrayList) map.get("slot");
            ArrayList tempSlot = new ArrayList();
            for (int i = 1; i <= 15; i++) {
                tempSlot.add(slot.contains(i));
            }
            map.replace("slot", tempSlot);
        }
        return result;
    }

    @Override
    public void updateSchedule(Map param) {
        ArrayList<DoctorWorkPlanScheduleEntity> addList = this.insertOrDeleteScheduleHandler(param);
        //将添加的时间段缓存到redis里
        this.addScheduleCache(addList);
    }

    @Override
    @Transactional
    public void deleteByWorkPlanId(int workPlanId) {
        ArrayList<HashMap> list = doctorWorkPlanScheduleDao.searchByWorkPlanId(workPlanId);
        doctorWorkPlanScheduleDao.deleteByWorkPlanId(workPlanId);
        list.forEach(one->{
            int scheduleId = MapUtil.getInt(one,"scheduleId");
            String key = "doctor_schedule_" + scheduleId;
            redisTemplate.delete(key);
        });
    }


    @Transactional
    public ArrayList<DoctorWorkPlanScheduleEntity> insertOrDeleteScheduleHandler(Map param){
        //更新人数上限
        doctorWorkPlanDao.updateMaximum(param);
        Integer workPlanId = MapUtil.getInt(param,"workPlanId");
        Integer maximum = MapUtil.getInt(param,"maximum");

        //待处理的时间段
        ArrayList<DoctorScheduleSlotVO> slots = (ArrayList<DoctorScheduleSlotVO>) param.get("slots");
        ArrayList<DoctorWorkPlanScheduleEntity> addList = new ArrayList();
        ArrayList<Integer> removeList = new ArrayList();
        //分析哪些添加哪些删除
        slots.forEach(one->{
            if(one.getOperate().equals("insert")){
                DoctorWorkPlanScheduleEntity entity = new DoctorWorkPlanScheduleEntity();
                entity.setWorkPlanId(workPlanId);
                entity.setMaximum(maximum);
                entity.setSlot(one.getSlot());
                addList.add(entity);
            }else {
                removeList.add(one.getScheduleId());
            }
        });
        if(!removeList.isEmpty()){
            //查询这些待删除时间段的挂号总人数
            if(doctorWorkPlanScheduleDao.searchSumNumByIds(removeList)>0)
                throw new HospitalException("修改失败,已经有人挂号");

            doctorWorkPlanScheduleDao.deleteByIds(removeList);
            //删除redis上的缓存
            removeList.forEach(one->{
                String key = "doctor_schedule_" + one;
                redisTemplate.delete(key);
            });
        }

        addList.forEach(one->{
            doctorWorkPlanScheduleDao.insert(one);
        });
        return addList;
    }
}
